import os
import cv2
import numpy as np
import logging
from colorlog import ColoredFormatter


def get_logger(name=__name__):
    logger_base = logging.getLogger(name)
    logger_base.setLevel(logging.DEBUG)
    stream_handler = logging.StreamHandler()
    color_formatter = ColoredFormatter('%(log_color)s[%(module)-12s][%(funcName)-12s][%(levelname)-8s] %(message)s')
    # formatter = logging.Formatter('[%(module)-15s][%(funcName)-7s][%(levelname)-8s] %(message)s')
    stream_handler.setFormatter(color_formatter)
    logger_base.addHandler(stream_handler)
    return logger_base


logger = get_logger()


class HelperConfig:
    wait_time = 500
    # 最多等待一分钟就自动关闭
    wait_time_forever = 60000


class Show:
    class LineItem:
        def __init__(self, row: int = 0, height: int = 0, x: int = 0):
            self.row, self.height, self.x = row, height, x

        def __str__(self):
            return "Line[row=%s, height=%s, x=%s]" % (self.row, self.height, self.x)

    class RectItem:
        def __init__(self, x1: int = 0, y1: int = 0, x2: int = 0, y2: int = 0):
            self.x1, self.y1, self.x2, self.y2 = x1, y1, x2, y2

        def to_tuple(self) -> tuple:
            return self.x1, self.y1, self.x2, self.y2

    offset = (300, 150)
    resize = 4
    starts = []

    @staticmethod
    def window_insert(row: int, width: int, height: int):
        found = False
        y = 0
        for i in range(len(Show.starts)):
            if Show.starts[i].row == row:
                found = True
                Show.starts[i].height = max(Show.starts[i].height, height)
                Show.starts[i].x += width
                y = i
                break
        if not found:
            Show.starts.append(Show.LineItem(row=row, height=height, x=width))
            Show.starts.sort(key=lambda x: x.row)
            y = len(Show.starts) - 1
        y_sum = sum([Show.starts[i].height for i in range(y)])
        return Show.RectItem(Show.starts[y].x - width, y_sum,
                             Show.starts[y].x, y_sum + height)

    @staticmethod
    def window_clear():
        cv2.destroyAllWindows()
        Show.starts = []

    @staticmethod
    def imshow(window_name: str, im: np.ndarray, row: int = 0):
        window_name = window_name.encode('gbk').decode('utf8', errors='ignore')
        # logger.debug('im.shape: %s' % str(im.shape))
        im = cv2.resize(im, (im.shape[1] // Show.resize, im.shape[0] // Show.resize))
        im_size = im.shape
        rect = Show.window_insert(row, im_size[1], im_size[0])
        cv2.imshow(window_name, im)
        cv2.moveWindow(window_name, rect.x1 + Show.offset[0], rect.y1 + Show.offset[1])
        # logger.debug('starts now: %s' % [str(i) for i in Show.starts])


class Controls:
    @staticmethod
    def wait_exit(wait_time: int = HelperConfig.wait_time, key: int = 27):
        wait_time = HelperConfig.wait_time_forever if wait_time == 0 else wait_time
        if cv2.waitKey(wait_time) == key:
            Controls.exit_kill()

    # 干掉最后一个python进程
    @staticmethod
    def exit_kill():
        result = os.popen('wmic process where name="python.exe" list brief')
        data = result.read().split('\n')
        pid = [d.split() for d in data if len(d) != 0 and data.index(d) != 0][-1][3]
        logger.warning('Try to kill PID:%s...' % pid)
        result = os.popen("taskkill.exe /f /pid %s" % pid)
        logger.critical('result: %s' % result.read())


class Utils:
    @staticmethod
    def extend_line(x1, y1, x2, y2, x, y, flag=1, k_=None):
        if flag == 1:
            if y1 == y2:
                return 0, y1, x, y2
            else:
                k = ((y2 - y1) / (x2 - x1) if x2 - x1 != 0 else 1000) if k_ is None else k_
                b = (x1 * y2 - x2 * y1) / (x1 - x2) if x2 - x1 != 0 else 1000
                x3 = 0
                y3 = b
                x4 = x
                y4 = int(k * x4 + b)
            return x3, y3, x4, y4
        else:
            if x1 == x2:
                return x1, 0, x2, y
            else:
                k = ((y2 - y1) / (x2 - x1) if x2 - x1 != 0 else 1000) if k_ is None else k_
                b = (x1 * y2 - x2 * y1) / (x1 - x2) if x2 - x1 != 0 else 1000
                y3 = 0
                x3 = int(-1 * b / k)
                y4 = y
                x4 = int((y4 - b) / k)
                return x3, y3, x4, y4
